﻿using Microsoft.EntityFrameworkCore;
using System.Data;
using GatewayServerService.Data;
using UtilsCache;
using GatewayServerService.Device;
using UtilsBase;
using UtilsORM;
using UtilsORM.MySqlData;
using Models.Common;
using Newtonsoft.Json;
using Models.Device;
using System.Diagnostics;
using System.Timers;
using System.Reflection.Metadata;
using System.Collections.Generic;
using System;
using AngleSharp.Dom;


namespace GatewayServerService.CloudCenter
{
    /// <summary>
    /// 场景 查询某设备的所有条件配置出来，进行条件匹配，并执行处理
    /// </summary>
    public class ServiceCloudLinkageCondition
    {

        #region
        /// <summary>
        /// 查询设备对应的所有条件出来
        /// </summary>
        /// <param name="deviceGuid"></param>
        /// <param name="executeType">0自动运行，1手动运行</param>
        public void linkageConditionAutoRun(string deviceGuid)
        {
            //检测是否正在处理中

            try
            {
                List<iot_device_linkage> linkpagelist = UtilMemoryCacheHelper.get<List<iot_device_linkage>>("iot_device_linkage" + deviceGuid);
                if (linkpagelist == null)
                {
                    EFYihongIotContext ef = new EFYihongIotContext();
                    //查出这个设备所有条件
                    linkpagelist = (from lk in ef.iot_device_linkage
                                    join lkc in ef.iot_device_linkage_condition
                                    on lk.l_guid equals lkc.lc_l_guid
                                    where lkc.lc_d_guid == deviceGuid && lkc.lc_operation == "main" && lk.l_status == 0 && lk.l_auto_run == 0 && lkc.lc_status == 0
                                    select lk).Distinct().ToList();
                    ef.Dispose();
                    UtilMemoryCacheHelper.set("iot_device_linkage" + deviceGuid, linkpagelist);
                }
                foreach (iot_device_linkage item in linkpagelist)
                {
                    linkage(item);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("  LinkageCondition -----error-------" + ex);
            }

        }

        /// <summary>
        ///处理条件任务，判断条件是否成立
        /// </summary>
        /// <param name="item"></param>
        public void linkage(iot_device_linkage item)
        {

            EFYihongIotContext ef = new EFYihongIotContext();
           
            //判断是否已经正在执行，如果有，就不执行下面了
            iot_device_linkage_condition_handle handleing = ef.iot_device_linkage_condition_handle.Where(c => c.lc_l_guid == item.l_guid).FirstOrDefault();
            if (handleing != null)
            {
                return;
            }
          


            try
            {
                List<iot_device_linkage_condition> operationMainList = new DBIotDeviceLinkageConditionCache().GetLinkage_Condition(item.l_guid).Where(c => c.lc_operation == "main").ToList();
                //条件判断
                bool isTrue = false;

                foreach (iot_device_linkage_condition itemoperation in operationMainList)
                {
                    //条件判断是否为真                    
                    isTrue = getValueMatch(itemoperation);
                    if (isTrue)
                    {
                        //成立 判断是否or
                        if (item.l_condition_type == "or")
                        {
                            break;
                        }
                    }
                    else
                    {
                        //不成立 // 条件为and
                        if (item.l_condition_type == "and")
                        {
                            break;
                        }
                    }

                }

                //判断是否or 或and
                if (isTrue)
                {
                    //条件成立,执行下一步
                    insert_linkageCondition(item);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                new DBIotSystemLogError().addSystemLogError("linkage 条件处理失败，l_guid:" + item.l_guid, ex.ToString());
            }



        }

        /// <summary>
        /// 写入待处理表
        /// </summary>
        /// <param name="item"></param>
        public void insert_linkageCondition(iot_device_linkage item)
        {
            try
            {
                EFYihongIotContext ef = new EFYihongIotContext();
                List<iot_device_linkage_condition> operationFollowList = new DBIotDeviceLinkageConditionCache().GetLinkage_Condition(item.l_guid).Where(c => c.lc_operation == "follow").OrderBy(c => c.lc_order).ToList();

                using (EFYihongIotContext efTran = new EFYihongIotContext())
                {
                    using (var tran = efTran.Database.BeginTransaction())
                    {

                        try
                        {

                            //执行内容
                            foreach (iot_device_linkage_condition itemfollowoperation in operationFollowList)
                            {
                                //增加处理记录
                                
                                addConditionHandle(itemfollowoperation, efTran);

                                efTran.iot_device_linkage.Where(c => c.l_guid == itemfollowoperation.lc_l_guid).
                    ExecuteUpdate(c => c.SetProperty(p => p.l_execute_time, DateTime.Now)); /// 更新执行状态                         
                            }
                            tran.Commit();
                            tran.Dispose();
                        }
                        catch (Exception ex)
                        {
                            tran.Rollback();
                            tran.Dispose();
                            return;
                        }

                    }
                }


            }
            catch (Exception ex)
            {
                Console.WriteLine("  LinkageCondition -----error-------" + ex);
                new DBIotSystemLogError().addSystemLogError("execute_linkageCondition_forDevice 条件处理失败，l_guid:" + item.l_guid, ex.ToString());
            }

        }
        #endregion

        /// <summary>
        /// 匹配条件是否已经满足
        /// </summary>
        /// <param name="itemoperation"></param>
        /// <returns></returns>
        protected bool getValueMatch(iot_device_linkage_condition itemoperation)
        {

            //查询当前温度是否到设置值，取ServiceCloudDeviceValueLog中设置的redis值
            string dvalue = new DBIotDeviceValueCurrentCache().getDeviceValue(itemoperation.lc_d_guid, itemoperation.lc_key);// UtilMemoryCacheHelper.get<string>("deviceKey_" + itemoperation.lc_d_guid + itemoperation.lc_key);
            if (string.IsNullOrEmpty(dvalue))
            {
                Console.WriteLine(" 条件判断 dvalue 空");
                return false;
            }


            string valueTypeByKey = new DBIotDeviceVariableCache().getValueTypeByKey(itemoperation.lc_key);
            if (valueTypeByKey != null)
            {
                if (valueTypeByKey == "number")
                {
                    if (itemoperation.lc_value_rule == ">")
                    {
                        if (double.Parse(dvalue) > double.Parse(itemoperation.lc_value))
                        {
                            return true;
                        }
                    }
                    else if (itemoperation.lc_value_rule == "=")
                    {
                        if (double.Parse(dvalue) == double.Parse(itemoperation.lc_value))
                        {
                            return true;
                        }
                    }
                    else if (itemoperation.lc_value_rule == ">=")
                    {
                        if (double.Parse(dvalue) >= double.Parse(itemoperation.lc_value))
                        {
                            return true;
                        }
                    }
                    else if (itemoperation.lc_value_rule == "<")
                    {
                        if (double.Parse(dvalue) < double.Parse(itemoperation.lc_value))
                        {
                            return true;
                        }
                    }
                    else if (itemoperation.lc_value_rule == "<=")
                    {
                        if (double.Parse(dvalue) <= double.Parse(itemoperation.lc_value))
                        {
                            return true;
                        }
                    }
                }
                else
                {
                    if (itemoperation.lc_value_rule == "=")
                    {
                        if (dvalue == itemoperation.lc_value)
                        {
                            return true;
                        }
                    }
                    else if (itemoperation.lc_value_rule == "!=")
                    {
                        if (dvalue != itemoperation.lc_value)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;

        }

        /// <summary>
        /// 更新执行状态
        /// </summary>
        /// <param name="iot_Device_Linkage_Condition"></param>
        private void updateResult(iot_device_linkage_condition iot_Device_Linkage_Condition)
        {
            string sql = "update iot_device_linkage set l_execute_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' where l_guid='" + iot_Device_Linkage_Condition.lc_l_guid + "' ";
            new MySqlYihongIot().Db.Ado.ExecuteCommand(sql);
        }


        /// <summary>
        /// 一般通道写入
        /// </summary>
        /// <param name="model"></param>

        public void addConditionHandle(iot_device_linkage_condition model, EFYihongIotContext efTran)
        {


            iot_device_linkage_condition_handle handle = new UtilsClassClone().CloneByReflection<iot_device_linkage_condition, iot_device_linkage_condition_handle>(model);
            handle.lc_add_time = DateTime.Now;
            handle.lc_id = 0;
            handle.lc_status = 0;
            efTran.iot_device_linkage_condition_handle.Add(handle);
            efTran.SaveChanges();

        }


        private static object obj = new object();
        /// <summary>
        /// 一般通道-执行条件触发
        /// </summary>
        public void doConditionHandle()
        {

            //加锁同时只能执行一个,多节点时这里要改成redis锁
            lock (obj)
            {
                string doresult = "";
                EFYihongIotContext ef = new EFYihongIotContext();
                //lc_status == 0 是同一条件表，所有处理项都写入了的意思，上面用到，不能去掉
                List<iot_device_linkage_condition_handle> conditions = ef.iot_device_linkage_condition_handle.Where(c => c.lc_status == 0).OrderBy(c => c.lc_order).ToList();
                foreach (iot_device_linkage_condition_handle itemfollowoperation in conditions)
                {
                    try
                    {

                        doresult = "已执行";
                        //判断是否有东西没执完 ,,id越小，越先执行
                        iot_device_linkage_condition_handle hasChild = conditions.Where(c => c.lc_l_guid == itemfollowoperation.lc_l_guid && c.lc_id < itemfollowoperation.lc_id).FirstOrDefault();
                        if (hasChild != null)
                        {
                            continue;
                        }

                        if (itemfollowoperation.lc_key == "delay")
                        {
                            //判断是否够时间了
                            DateTime doTime = Convert.ToDateTime(itemfollowoperation.lc_add_time).AddSeconds(double.Parse(itemfollowoperation.lc_value));
                            if (doTime > DateTime.Now)
                            {
                                //还没到执行时间
                                continue;
                            }
                        }
                        else
                        {
                            //如果数据欠缺，补全 默认1次，10秒
                            if (itemfollowoperation.lc_repeat_count == null)
                            {
                                itemfollowoperation.lc_repeat_count = 1;
                            }
                            if (itemfollowoperation.lc_repeat_interval == null)
                            {
                                itemfollowoperation.lc_repeat_interval = 10;
                            }
                            Task.Run(() =>
                            {
                                new ServiceCloudDeviceCommand().sendCommandToGateWay(itemfollowoperation.lc_d_guid, itemfollowoperation.lc_key, "条件触发器 lc_guid:" + itemfollowoperation.lc_guid.ToString(), "", (int)itemfollowoperation.lc_repeat_count, new UtilsDateTime().getIntervalSeccond((double)itemfollowoperation.lc_repeat_interval, "ss"));
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                    ef.iot_device_linkage_condition_handle.Where(c => c.lc_id == itemfollowoperation.lc_id).ExecuteDelete();
                    new DBIotDeviceLinkageConditionLog().addsync(itemfollowoperation, doresult + "-" + itemfollowoperation.lc_key + "-" + itemfollowoperation.lc_guid + "-" + itemfollowoperation.lc_add_time + "-" + DateTime.Now);

                }
            }
        }


        /// <summary>
        /// 自动定时执行条件任务
        /// </summary>
        public void taskRun()
        {
            try
            {
                new EFYihongIotContext().iot_device_linkage_condition_handle.ExecuteDelete();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }

            while (true)
            {
                try
                {
                    doConditionHandle();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
                Thread.Sleep(200);
            }
        }

    }
}
